﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace eventModel.util
{
    /// <summary>
    /// Allows you to maintain a link to typed objects after they are used in order to prevent garbage collection.  This allows the object memory to be reused on a later object of the same type putting less load on the Garbage Collector and allowing faster instantiation.
    /// </summary>
    /// <typeparam name="T">The type you wish to use with the factory.</typeparam>
    static class Factory<T> where T : new()
    {
        static Stack<T> _stack = new Stack<T>(100);
        static int capacity = 100;

        /// <summary>
        /// Gets or sets the initial capacity of the objects that the factory can hold.
        /// </summary>
        public static int Capacity
        {
            get
            {
                return capacity;
            }
            set
            {
                capacity = value;
                Stack<T> stack = new Stack<T>(value);
                while (_stack.Count > 0)
                    stack.Push(_stack.Pop());
            }
        }

        /// <summary>
        /// Pre-creates objects to be leased from the factory.
        /// </summary>
        public static void PreFill()
        {
            PreFill(capacity - _stack.Count);
        }

        /// <summary>
        /// Pre-creates objects to be leased from the factory.
        /// </summary>
        /// <param name="count">The number of objects to pre-create.</param>
        public static void PreFill(int count)
        {
            for (int i = 0; i < count; i++)
                _stack.Push(new T());
        }

        /// <summary>
        /// Gets an object from the factory.  Object members may retain old values when removing them from the factory and should be initialized, if needed, before use.
        /// </summary>
        /// <returns>The stored object to be reused.</returns>
        public static T Checkout()
        {
            T @object;
            if (_stack.Count > 0)
                @object = _stack.Pop();
            else
                @object = new T();
            return @object;
        }

        /// <summary>
        /// Returns an object to the factory for later reuse.
        /// </summary>
        /// <param name="object">The object to be returned.</param>
        public static void Return(T @object)
        {
            _stack.Push(@object);
        }
    }
}
